package gu.sql2java.pagehelper.aspect.spring;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import gu.sql2java.SimpleLog;
import gu.sql2java.pagehelper.PageHelper;
import gu.sql2java.pagehelper.annotations.Sql2javaEnablePage;
import gu.sql2java.wherehelper.WhereHelper;
import gu.sql2java.wherehelper.WhereHelpers;
import gu.sql2java.wherehelper.annotations.EnableWhereHelper;

import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;

import static com.google.common.base.Strings.isNullOrEmpty;

import static com.google.common.base.MoreObjects.firstNonNull;
@Component
public class PageHelperAop{
	
	/**
	 * PageHelper切面执行<br>
	 * 对于有{@link Sql2javaEnablePage}注解的方法,
	 * 且从HTTP请求头中能读取{@code pageNumKey},{@code pageSizeKey}指定的属性,
	 * 分别作为{@code pageNum}(页码参数),{@code pageSize}(每页显示数量),
	 * 则自动调用{@link PageHelper#startPage(int, int)}启动分页查询<br>
	 * 如果方法定义了{@link EnableWhereHelper}注解则会自动创建{@link WhereHelper}实例，
	 * 根据方法注解提供参数定义动态生成SQL WHRE语句,
	 * 参见 {@code gu.sql2java.wherehelper.annotations}中定义的WhereHelper注解
	 * @param joinPoint
	 * @return 返回执行服务方法调用的返回值
	 * @throws Throwable
	 */
	public Object pageHelperAround(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature methodSignature = (MethodSignature)joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        Sql2javaEnablePage enablePage = method.getAnnotation(Sql2javaEnablePage.class);
        if(null == enablePage  || !enablePage.value() || isNullOrEmpty(enablePage.pageNumKey()) || isNullOrEmpty(enablePage.pageSizeKey())){
        	PageHelper.setEnable(false);
        	buildWhereHelperIfEnable(joinPoint);
        	/** 未激活PageHelper 直接调用原方法 */
            try {
            	return joinPoint.proceed();
    		} finally {
    			/** 清除ThreadLocal变量 */
    			PageHelper.clearPage();
    		}
        }
        /**
         * PageHelper激活
         */
        boolean startPage = false;
        try {
        	/** 从注解中获取PageHelper必要参数所需要的参数名 */
        	String pageNumKey = enablePage.pageNumKey();
        	String pageSizeKey = enablePage.pageSizeKey();
        	String countKey = enablePage.countKey();
        	HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        	/** 从HTTP请求中获取起始页，每页长度参数 */
        	String pageNum = firstNonNull(request.getParameter(pageNumKey),"1");
        	String pageSize = firstNonNull(request.getParameter(pageSizeKey),"10");
        	if(!isNullOrEmpty(pageNum) && !isNullOrEmpty(pageSize)){
        		String count;
        		boolean docount= true;
        		if(!isNullOrEmpty(countKey) && null != (count = request.getParameter(countKey))){
        			docount = Boolean.valueOf(count);
        		}
        		PageHelper.startPage(Integer.valueOf(pageNum), Integer.valueOf(pageSize),docount);
        	}
        	buildWhereHelperIfEnable(joinPoint);
        	/** 设置PageHelper启动成功标志 */
        	startPage = true;
		} catch (Exception e) {
			SimpleLog.log(e);
		}finally{
			if(!startPage){
				/** 初始化出错,清除ThreadLocal变量 */
				PageHelper.clearPage();
			}
		}
        try {
        	return joinPoint.proceed();
		} finally {
			/** 清除ThreadLocal变量 */
			PageHelper.clearPage();
		}
    }
	/**
	 * 如果服务方法有{@link EnableWhereHelper}注解,启动WhereHelper生成WHERE SQL语句
	 * @param joinPoint
	 */
	private static void buildWhereHelperIfEnable(ProceedingJoinPoint joinPoint){
		MethodSignature methodSignature = (MethodSignature)joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    	WhereHelper whereHelper = WhereHelpers.buildWhereHelperIfEnable(method, 
    			/**
				 * 将从服务方法的参数注入WhereHelper
				 */
    			joinPoint.getArgs(), 
    			/**
    			 * 将从服务HTTP请求(GET)中获取的参数注入WhereHelper,
    			 * 如果服务方法参数和GET参数中有共同的参数则以GET参数优先
    			 */
    			request::getParameter);
    	if(null != whereHelper){
    		PageHelper.setWhere(whereHelper.where());
    	}
	}
}
